def fun1(func):
    print("enter fun1")

    def inner_fun1(*args, **kwargs):
        print("inner fun1 start")
        return func(*args, **kwargs)

    return inner_fun1


def fun2(func):
    print("enter fun2")

    def inner_fun2(*args, **kwargs):
        print("inner fun2 start")
        return func(*args, **kwargs)

    return inner_fun2


@fun2
@fun1
def demo(*args, **kwargs):
    print("start demo")


demo("I am demo")

"""
    两层注解相当于：
    demo = fun2(fun1(demo))
    解开的步骤如下：
    1、加上 fun1 注解
        进入 fun1 函数，执行 print("enter fun1")
        构造 inner_fun1 函数。这时候因为构造函数，没有执行。构造函数里面包含了 print("inner fun2 start")
        返回的 inner_fun1 相当于:
        {
            print("inner fun1 start")
            demo # 这里把 demo 作为地址带入
        }
    2、加上 fun2 注解
        进入 fun2 函数，执行 print("enter fun2")
        然后再包裹带入的 demo 函数。这时候带入的 demo 相当于：
        {
            print("inner fun1 start")
            demo # 这里把 demo 作为地址带入
        }
        就是上面包裹的函数
        包裹之后，返回的函数变成了：
        {
            print("inner fun2 start")
            print("inner fun1 start")
            demo
        }
    3、执行 demo()
    这时候开始执行上面包裹好的函数。所有顺序打印的结果是
    enter fun1
    enter fun2
    inner fun2 start
    inner fun1 start
    start demo

    总结一下就是，先注解的，闭包之前的代码先执行，闭包代码离包裹函数最近，后执行
"""
